﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Device.Location;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Maps;


namespace TourGuideApp
{
    public partial class GuidePage : PhoneApplicationPage, INotifyPropertyChanged
    {
        #region Consts
        /// <value>Default map zoom level.</value>
        private const double DefaultZoomLevel = 18.0;

        /// <value>Maximum map zoom level allowed.</value>
        private const double MaxZoomLevel = 21.0;

        /// <value>Minimum map zoom level allowed.</value>
        private const double MinZoomLevel = 10.0;

        private List<GeoCoordinate> stopsGeoCoordinates = new List<GeoCoordinate>();

        #endregion

        #region Properties and Fields
        internal Credentials _cdntls = new Credentials() { ApplicationId = App.Id };
        internal Credentials Cdntls { get { return _cdntls; } }

        internal readonly CredentialsProvider _cp = new ApplicationIdCredentialsProvider(App.Id);
        internal CredentialsProvider CP { get { return _cp; } }

        /// <summary>
        /// Gets or sets the map zoom level.
        /// </summary>
        private double _zoom = 18;
        public double Zoom
        {
            get { return _zoom; }
            set
            {
                var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value));
                if (_zoom != coercedZoom)
                {
                    _zoom = value;
                    NotifyPropertyChanged("Zoom");
                }
            }
        }

        /// <summary>
        /// Gets or sets the map center location coordinate.
        /// </summary>
        private GeoCoordinate _center = new GeoCoordinate(45.4237, -75.68321);
        public GeoCoordinate Center
        {
            get { return _center; }
            set
            {
                if (_center != value)
                {
                    _center = value;
                    NotifyPropertyChanged("Center");
                }
            }
        }

        internal GeoCoordinateWatcher _geoCoordinateWatcher;
        internal GeoCoordinateWatcher Watcher { get { return _geoCoordinateWatcher; } }

        private Bing.Route.RouteServiceClient _routeClient;


        #endregion

        #region Methods and Event Handlers

        public GuidePage()
        {
            InitializeComponent();

        }

        // This _geoCoordinateWatcher_PositionChanged logic can get irritating to the user if the user wants to check other locations on the map
        // after road testing we decide what we do in this regarding the setting the map center.
        void _geoCoordinateWatcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            Center = e.Position.Location;
            //setClosestStop();//it should do something only if the closest stop changed due to user movement
            //TODO: update user pushpin
            //TODO: update route pushpins visited indicators

        }

        void drawRoute(List<GeoCoordinate> geocoordinates)
        {
            //Locations to waypoints

            ObservableCollection<Bing.Route.Waypoint> waypoints = new ObservableCollection<Bing.Route.Waypoint>();
            foreach (var g in geocoordinates)
            {
                var w = new Bing.Route.Waypoint();
                w.Description = g.ToString();
                w.Location = g;
                waypoints.Add(w);

                //Draw waypoints (stop locations)
                Ellipse point = new Ellipse();
                point.Width = 20;
                point.Height = 20;
                point.Fill = new SolidColorBrush(Colors.Orange);
                point.Opacity = 0.95;

                point.Tag = g;

                RouteLayer.AddChild(point, g);
            }

            var request = new Bing.Route.RouteRequest()
            {
                Culture = System.Globalization.CultureInfo.CurrentCulture.Name,
                Waypoints = waypoints,
                ExecutionOptions = new Bing.Route.ExecutionOptions() { SuppressFaults = true },
                Options = new Bing.Route.RouteOptions() { RoutePathType = Bing.Route.RoutePathType.Points },
                Credentials = new Credentials() { ApplicationId = App.Id },
            };

            _routeClient.CalculateRouteAsync(request);

        }

        private void client_RouteCompleted(object sender, Bing.Route.CalculateRouteCompletedEventArgs e)
        {
            if (e.Result.ResponseSummary.StatusCode == Bing.Route.ResponseStatusCode.Success)
            {
                var result = e.Result;
                MapPolyline routeLine = new MapPolyline();
                routeLine.Locations = new LocationCollection();
                routeLine.Stroke = new SolidColorBrush(Colors.Blue);
                routeLine.Opacity = 0.65;
                routeLine.StrokeThickness = 5.0;

                foreach (var p in result.Result.RoutePath.Points)
                {
                    routeLine.Locations.Add(new GeoCoordinate(p.Latitude, p.Longitude));
                }

                foreach (var itineraryItem in result.Result.Legs[0].Itinerary)
                {
                    Ellipse point = new Ellipse();
                    point.Width = 10;
                    point.Height = 10;
                    point.Fill = new SolidColorBrush(Colors.Red);
                    point.Opacity = 0.65;

                    GeoCoordinate location = new GeoCoordinate(itineraryItem.Location.Latitude, itineraryItem.Location.Longitude);
                    point.Tag = itineraryItem;

                    RouteLayer.AddChild(point, location);
                }

                RouteLayer.Children.Add(routeLine);
                var viewRect = LocationRect.CreateLocationRect(routeLine.Locations);
                guideMap.SetView(viewRect);
            }
            else
            {
                MessageBox.Show("Error retrieving the route: " + e.Result.ResponseSummary.FaultReason);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            _geoCoordinateWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
            _geoCoordinateWatcher.MovementThreshold = 10;
            _geoCoordinateWatcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(_geoCoordinateWatcher_PositionChanged);
            _geoCoordinateWatcher.Start();

            //Center = _geoCoordinateWatcher.Position.Location;
            Center = new GeoCoordinate(45.4237, -75.68321);
            Zoom = 18;

            var tourSource = (Expression.Blend.SampleData.TourSampleDataSource.toursList)App.Current.Resources["TourSampleDataSource"];
            var stopcollection = tourSource.tourCollection[App.tourIndex].stopCollection;
            foreach (var s in stopcollection)
            {
                stopsGeoCoordinates.Add(new GeoCoordinate(s.location.latitude, s.location.longitude));
            }
            _routeClient = new Bing.Route.RouteServiceClient("BasicHttpBinding_IRouteService");
            _routeClient.CalculateRouteCompleted += new EventHandler<Bing.Route.CalculateRouteCompletedEventArgs>(client_RouteCompleted);
            //setClosestStop();
            drawRoute(stopsGeoCoordinates);
            //drawPushPins();

            DataContext = this;
        }
    }
}